package iks.sound 
{
	import flash.events.*;
	import flash.media.*;
	import iks.iface.*;

	/**
	 * 声音通道类, 由一个 Sound 对象作为音源, 可以限制该音源最多发出的声道个数
	 * @author StefanieKaka
	 */
	public final class KSound implements IKDispose
	{
		/**
		 * 构造函数
		 * @param	sound 音源对象
		 * @param	maxChannels 允许的同时播放的最大通道数
		 */
		public function KSound(sound : Sound, maxChannels : int) 
		{
			if (sound == null)
				throw new Error("Sound 对象不能为 null");
				
			if (maxChannels < 0)
				throw new Error("允许的最大通道数不能为负");
			
			if (!isFinite(maxChannels))
				throw new Error("通道数量必须是有限值");
				
			m_sound = sound;
			m_maxChannels = maxChannels;
			m_channels = new Vector.<SoundChannel>();
			m_loops = new Vector.<Number>();
		}
		
///////////////////////////////////////////////////////////////////////////////////////////////////
// 公共域
///////////////////////////////////////////////////////////////////////////////////////////////////
		
		/**
		 * 播放声音
		 * @param	startTime 应开始回放的初始位置（以毫秒为单位）。 
		 * @param	loops 定义在声道停止回放之前，声音循环回 startTime 值的次数。
		 * @param	sndTransform 分配给该声道的初始 SoundTransform 对象。  
		 */
		public function play(startTime : Number = 0, loops : int = 0, sndTransform : SoundTransform = null) : void
		{
			m_pauseInfo = null;
			if (m_maxChannels > m_channels.length)
			{
				var soundChannel : SoundChannel = m_sound.play(startTime, loops, sndTransform);
				if (soundChannel != null)
					addChannel(soundChannel, startTime, loops, sndTransform);
			}
		}
		
		/**
		 * 停止该音源发出的所有声音
		 */
		public function stop() : void
		{
			m_pauseInfo = null;
			while (m_channels.length != 0)
				removeChannelAt(m_channels.length - 1);
		}
		
		/**
		 * 暂停所有声音, 暂停之后如果继续调用 play() 方法, 不会播放声音, 直到调用 resume() 恢复播放
		 */
		public function pause() : void
		{
			m_pauseInfo = new Vector.<SoundInfo>(m_channels.length, true);
			while (m_channels.length != 0)
			{
				var idx : int = m_channels.length - 1;
				m_pauseInfo[idx] = new SoundInfo(m_channels[idx].position, m_loops[idx], m_channels[idx].soundTransform);
				removeChannelAt(idx);
			}
		}
		
		/**
		 * 继续播放
		 */
		public function resume() : void
		{
			for each (var info : SoundInfo in m_pauseInfo)
			{
				var channel : SoundChannel = m_sound.play(info.position, info.loops, info.sndTransform);
				if (channel != null)
					addChannel(channel, info.position, info.loops, info.sndTransform);
			}
			m_pauseInfo = null;
		}
		
		/**
		 * 设置音量
		 * @param	volume 音量
		 * @param	panning 左右声道的偏移量
		 */
		public function setVolume(volume : Number = 1, panning : Number = 0) : void
		{
			for each (var channel : SoundChannel in m_channels)
				channel.soundTransform = new SoundTransform(volume, panning);
				
			for each (var info : SoundInfo in m_pauseInfo)
				info.sndTransform = new SoundTransform(volume, panning);
		}
		
		/// 声源对象
		public function get sound() : Sound
		{
			return m_sound;
		}
		
		/**
		 * 同时允许播放的最大通道数量, 如果更改此属性, 将停止当前播放的所有声音, 直到再调用 play() 方法
		 */
		public function get maxChannels() : int
		{
			return m_maxChannels;
		}
		
		public function set maxChannels(value : int) : void
		{
			m_maxChannels = value;
			
			stop();
		}
		
///////////////////////////////////////////////////////////////////////////////////////////////////
// 实现 IKDispose 接口
///////////////////////////////////////////////////////////////////////////////////////////////////
		
		public function dispose() : void
		{
			if (m_isDisposed)
				return;
			m_isDisposed = true;
			
			stop();
			m_channels = null;
			m_loops = null;
			m_pauseInfo = null;
			m_sound = null;
		}

///////////////////////////////////////////////////////////////////////////////////////////////////
// 私有域
///////////////////////////////////////////////////////////////////////////////////////////////////

		/// 添加声道对象
		private function addChannel(channel : SoundChannel, startTime : Number, loops : int, sndTransfor : SoundTransform) : void
		{
			channel.addEventListener(Event.SOUND_COMPLETE, onSoundCompleteHandler);
			m_channels.push(channel);
			m_loops.push(loops);
		}

		/// 移除声道
		private function removeChannelAt(idx : int) : void
		{
			m_channels[idx].stop();
			m_channels[idx].removeEventListener(Event.SOUND_COMPLETE, onSoundCompleteHandler);
			m_channels.splice(idx, 1);
			m_loops.splice(idx, 1);
		}
		
		/// 移除声道
		private function removeChannel(channel : SoundChannel) : void
		{
			removeChannelAt(m_channels.indexOf(channel));
		}
		
		/// 声音播放结束
		private function onSoundCompleteHandler(evt : Event) : void
		{
			removeChannel(evt.target as SoundChannel);
		}

		private var m_isDisposed	: Boolean = false;
		private var m_sound			: Sound = null;
		private var m_maxChannels	: int = 0;
		private var m_channels		: Vector.<SoundChannel> = null;
		private var m_loops			: Vector.<Number> = null;
		private var m_pauseInfo		: Vector.<SoundInfo> = null;
		
	}

}

import flash.media.*;

class SoundInfo
{
	public function SoundInfo(position : Number, loops : int, sndTransform : SoundTransform)
	{
		m_position = position;
		m_loops = loops;
		m_sndTransform = sndTransform;
	}
	
///////////////////////////////////////////////////////////////////////////////////////////////////
// 公共域
///////////////////////////////////////////////////////////////////////////////////////////////////
	
	/// 当前播放位置
	public function get position() : Number
	{
		return m_position;
	}
	
	/// 循环次数
	public function get loops() : int
	{
		return m_loops;
	}
	
	/// 声道 SoundTransform 对象
	public function get sndTransform() : SoundTransform
	{
		return m_sndTransform;
	}
	
	public function set sndTransform(value : SoundTransform) : void
	{
		m_sndTransform = value;
	}

///////////////////////////////////////////////////////////////////////////////////////////////////
// 私有域
///////////////////////////////////////////////////////////////////////////////////////////////////
	
	private var m_position		: Number = 0;
	private var m_loops			: int = 0;
	private var m_sndTransform	: SoundTransform = null;

}































///////////////////////////////////////////////////////////////////////////////////////////////////
// end file